; 1 accumulator
(define (make-accumulator state)
    (lambda (num) 
        (set! state (+ state num) )
        state
    )
)
(define A (make-accumulator 0))
(A 10)
(A 20)

; 2 count # of times a given procedure been called
; define a make-monitored: f -> mf, which act like a decorator
; mf will have an internal counter; f only have one params
(define (make-monitored f)
    (let ((counter 0))
        (lambda (x) 
            (begin
                (cond ((eq? x 'how-many-calls?) counter)
                    ((eq? x 'reset-count) (set! counter 0) )
                    (else 
                        (begin
                            (set! counter (+ counter 1))
                            (f x)
                        )
                    )
                )
            )
        )
    )
)
(define (f x) x)
(define mf (make-monitored f))
(mf 10)
(mf 10)
(mf 'how-many-calls?)
(mf 'reset-count)
(mf 'how-many-calls?)

; 3 make-account to have password
; password should be a symbol
; doing wrong for seven times will call the cops
(define (make-account balance password)
    (define (withdraw money)
        (if (>= balance money)
            (begin
                (set! balance (- balance money))
                balance
            )    
            "Insufficient Fund!"
        )
    )
    (define (deposit money)
        (begin
            (set! balance (+ balance money))
            balance
        )
    )
    (let ((wrong 0))
        (define (call-the-cop x) 
            (begin
                "Calling Police Now"
            )
        )
        (define (dispatch p m)
            (if (eq? p password)
                (begin
                    (set! wrong 0)
                    (cond ((eq? m 'withdraw) withdraw)
                        ((eq? m 'deposit) deposit)
                        ((eq? m 'check) #t)
                    )    
                )
                (begin
                    (set! wrong (+ wrong 1))
                    (if (>= wrong 3)
                        call-the-cop
                        (if (eq? m 'check)
                            #f
                            (lambda (x) "Incorrect Password!")
                        )
                    )
                )
            )
        )
        dispatch
    )
)
(define acc (make-account 100 'hjc2000))
((acc 'hjc200 'withdraw) 50)

; 7 joint account
(define (make-adjoint acc password new-password)
    (define (dispatch p m)
        (if (eq? p new-password)
            (acc password m)
            "Incorrect Password"
        )
    )
    (if (acc password 'check)
        dispatch
        "Incorrect Password"
    )
)
(define acc_share (make-adjoint acc 'hjc2000 'dlm2000))
((acc_share 'dlm2000 'deposit) 10000)


; 8 test the evaluation order: left-first or right first
(define (f x)
    (let ((state 0))
        (if (= 0 state)
                (begin
                    (set! state (+ 1 state))
                    state
                )
               state 
        )
    )
)
(+ (f 0) (f 1))
; testing result: left-first